/**
 * 通用工具函数
 * 提供日期格式化、时间范围计算等常用功能
 * 同时处理类型化数组等兼容性问题
 */

// polyfill 区域开始 - 确保类型化数组和AMD模块加载在不同环境下可用
try {
  // 优先尝试获取全局对象，支持多种运行环境
  const globalObj = typeof global !== 'undefined' ? global : 
                   (typeof wx !== 'undefined' ? 
                      (wx.__globalObject || {}) : {});
  
  // 为类型化数组提供polyfill，确保代码在不支持的环境中仍能运行
  const typeArrays = [
    'Int8Array', 'Uint8Array', 'Uint8ClampedArray',
    'Int16Array', 'Uint16Array', 'Int32Array', 'Uint32Array',
    'Float32Array', 'Float64Array'
  ];
  
  // 遍历所有类型化数组类型，确保它们在全局对象中存在
  typeArrays.forEach(typeName => {
    if (typeof globalObj[typeName] === 'undefined') {
      // 使用普通数组作为替代，简单实现polyfill
      try {
        globalObj[typeName] = Array;
      } catch (e) {
        console.error(`无法为 ${typeName} 提供polyfill:`, e);
      }
    }
  });
  
  // 确保AMD模块加载的define函数存在
  if (typeof globalObj.define === 'undefined') {
    try {
      // 简单实现define函数，支持基本的模块加载功能
      globalObj.define = function(name, deps, callback) {
        // 简单实现，直接执行回调
        if (typeof callback === 'function') {
          const dummyModules = Array(deps.length).fill({});
          callback.apply(null, dummyModules);
        } else if (typeof deps === 'function') {
          deps();
        }
        return null;
      };
      globalObj.define.amd = {};
    } catch (e) {
      console.error('无法为define提供polyfill:', e);
    }
  }
} catch (e) {
  // 如果整个polyfill过程失败，记录错误但不阻止后续代码执行
  console.error('初始化类型数组polyfill失败:', e);
}

/**
 * 日期格式化函数
 * 将日期对象转换为指定格式的字符串
 * 支持年(Y)、月(M)、日(D)、时(H)、分(m)、秒(s)、季度(q)等格式
 * 
 * @param {Date} date 日期对象
 * @param {String} fmt 格式化模式 'YYYY-MM-DD HH:mm:ss'
 * @returns {String} 格式化后的日期字符串
 */
const formatTime = (date, fmt = 'YYYY-MM-DD HH:mm:ss') => {
  // 参数默认值和类型转换处理
  if (!date) date = new Date()
  if (!(date instanceof Date)) date = new Date(date)
  
  // 定义格式化映射对象
  const o = {
    'M+': date.getMonth() + 1, // 月份
    'D+': date.getDate(), // 日
    'H+': date.getHours(), // 小时
    'm+': date.getMinutes(), // 分
    's+': date.getSeconds(), // 秒
    'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
    'S': date.getMilliseconds() // 毫秒
  }
  
  // 处理年份格式化
  if (/(Y+)/.test(fmt)) {
    fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
  }
  
  // 处理其他时间元素的格式化
  for (let k in o) {
    if (new RegExp('(' + k + ')').test(fmt)) {
      // 根据格式字符的长度决定是否需要补0
      fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
    }
  }
  
  return fmt
}

/**
 * 获取指定时间范围的开始和结束时间
 * 支持今天、昨天、本周、本月等常用时间范围
 * 
 * @param {String} type 类型：today/yesterday/thisWeek/thisMonth
 * @returns {Object} 包含开始和结束时间的对象
 */
const getTimeRange = (type) => {
  const now = new Date()
  const startDate = new Date()
  const endDate = new Date()
  
  // 根据类型设置不同的时间范围
  switch (type) {
    case 'today':
      // 今天从0点到23:59:59.999
      startDate.setHours(0, 0, 0, 0)
      endDate.setHours(23, 59, 59, 999)
      break
    case 'yesterday':
      // 昨天从0点到23:59:59.999
      startDate.setDate(now.getDate() - 1)
      startDate.setHours(0, 0, 0, 0)
      endDate.setDate(now.getDate() - 1)
      endDate.setHours(23, 59, 59, 999)
      break
    case 'thisWeek':
      // 本周从周一0点到当前日期的23:59:59.999
      // 周一为一周的开始
      const day = now.getDay() || 7
      startDate.setDate(now.getDate() - day + 1)
      startDate.setHours(0, 0, 0, 0)
      endDate.setHours(23, 59, 59, 999)
      break
    case 'thisMonth':
      // 本月从1号0点到月末23:59:59.999
      startDate.setDate(1)
      startDate.setHours(0, 0, 0, 0)
      endDate.setMonth(now.getMonth() + 1)
      endDate.setDate(0)
      endDate.setHours(23, 59, 59, 999)
      break
    default:
      break
  }
  
  // 返回时间范围对象
  return {
    startDate,
    endDate
  }
}

/**
 * 数组去重函数
 * 利用Set的唯一性特性实现数组去重
 * 
 * @param {Array} arr 需要去重的数组
 * @returns {Array} 去重后的数组
 */
const uniqueArray = (arr) => {
  return Array.from(new Set(arr))
}

/**
 * 防抖函数
 * 用于限制函数的频繁调用，在指定延迟后才执行
 * 常用于搜索输入、窗口调整等场景
 * 
 * @param {Function} fn 要执行的函数
 * @param {Number} delay 延迟时间，毫秒
 * @returns {Function} 包装后的函数
 */
const debounce = (fn, delay = 500) => {
  let timer = null
  return function() {
    // 保存函数调用时的上下文和参数
    const context = this
    const args = arguments
    
    // 如果已经设定过定时器，则清空上次的定时器
    if (timer) clearTimeout(timer)
    
    // 设置新的定时器
    timer = setTimeout(() => {
      fn.apply(context, args)
    }, delay)
  }
}

// 导出所有工具函数
module.exports = {
  formatTime,
  getTimeRange,
  uniqueArray,
  debounce
} 